﻿// DibBase.cpp: implementation of the CDibBaseBase class.
//
//////////////////////////////////////////////////////////////////////
#pragma comment(lib, "winmm.lib ")

#pragma comment(lib, "AviBaseUI.lib")
#pragma comment(lib, "ImageLib.lib")

#include "stdafx.h"
//#include "BaseTool.h"
#include "DibBase.h"

//#include "IBaseTool.h"
//#include "IMath.h"
//#include "IProgressBar.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDibBase::CDibBase()
{
	m_pBits = NULL;
	m_pBufBits = NULL;
	m_nLength = 0;
	m_nBitCount = 0;

	m_Size = CSize( 0, 0 );

	m_p8BitColors = NULL;
	m_bCreateFromJpg = false;
}

CDibBase::~CDibBase()
{
	Destroy();

	if( m_p8BitColors )
	{
		delete[] m_p8BitColors;
		m_p8BitColors = NULL;
	}
}

//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////

// 初始化
BOOL CDibBase::Create ( int nWidth, int nHeight, int nBitCount )
{
	Destroy ();

	m_nLength = RecLen( nWidth, nHeight, nBitCount );
	if( m_bCreateFromJpg )
	{
		// 限制一下大小，避免内存不足
		INT_PTR nMax = 1024 * 1024;
		nMax = nMax * 1024 * 4;
		if( m_nLength > nMax )
			return FALSE;
	}

	m_nBitCount = nBitCount;
	m_Size = CSize( nWidth, nHeight );

	if( !DoCreate() )
	{
		Destroy ();
		return FALSE;
	}
	return TRUE;
}

INT_PTR CDibBase::RecLen( int nWidth, int nHeight, int nBitCount )
{
	int byWidth = nWidth * (nBitCount/8);
	if( byWidth % 4 )
		byWidth = byWidth/4*4+4;
	return ((INT_PTR)byWidth) * nHeight;
}

void CDibBase::Create8BitColor(COLORREF* pBasicCrs, int nNum)
{
	if( !m_p8BitColors )
		m_p8BitColors = (COLORREF *)(new BYTE[ sizeof(COLORREF) * 256 ]);
	memset( m_p8BitColors, 0, sizeof(COLORREF) * 256 );
	if( nNum > 8 )
	{
		for(int i = 0; i < nNum; i++)
			m_p8BitColors[ i + 1 ] = pBasicCrs[ i ];
		return;
	}
	
	int bit = 1, i;
	for(i = 0; i < nNum; i++)
		m_p8BitColors[ bit << i ] = pBasicCrs[ i ];

	int nCount = bit << nNum;
	int r, g, b, n;
	for(i = 3; i < nCount; i++)
	{
		if( m_p8BitColors[ i ] != 0 )
			continue;

		r = g = b = n = 0;
		for(int j = 0; j < nNum; j++)
		{
			if( i & (bit << j) )
			{
				r += GetRValue( pBasicCrs[j] );
				g += GetGValue( pBasicCrs[j] );
				b += GetBValue( pBasicCrs[j] );
				n++;
			}
		}
		ASSERT( n > 0 );
		r = (int)((double)r/n);//IMath::Int( (double)r/n );
		g = (int)((double)g/n);// IMath::Int( (double)g/n );
		b = (int)((double)b/n);// IMath::Int( (double)b/n );
		m_p8BitColors[ i ] = RGB(r, g, b);
	}
}

COLORREF CDibBase::Get8BitColor(int iIndex)
{
	ASSERT( iIndex >= 0 && iIndex < 256 );
	if( m_p8BitColors )
		return m_p8BitColors[ iIndex ];
	return 0;
}

void CDibBase::Set8BitColor(int iIndex, COLORREF cr)
{
	ASSERT( iIndex >= 0 && iIndex < 256 );
	if( !m_p8BitColors )
	{
		m_p8BitColors = (COLORREF *)(new BYTE[ sizeof(COLORREF) * 256 ]);
		memset( m_p8BitColors, 0, sizeof(COLORREF) * 256 );
	}
	m_p8BitColors[ iIndex ] = cr;
}

#define RGB_BGR( color ) ((color >> 16) + (color & 0xff00) + ((color & 0xff) << 16))

void CDibBase::SetBitmapInfo(CDibBase::DIB_BITMAPINFO& bm, int nCy)
{
	ZeroMemory ( &bm, sizeof (BITMAPINFO) );

	bm.bm.bmiHeader.biSize			= sizeof(BITMAPINFOHEADER);
	bm.bm.bmiHeader.biWidth			= m_Size.cx;
	bm.bm.bmiHeader.biPlanes		= 1;
	bm.bm.bmiHeader.biBitCount		= m_nBitCount; //32; 
	bm.bm.bmiHeader.biCompression	= BI_RGB;

	if( nCy == 0 )
	{
		bm.bm.bmiHeader.biHeight		= -m_Size.cy; // '+': 显示时从下到上
		bm.bm.bmiHeader.biSizeImage		= (DWORD)m_nLength;
	}
	else
	{
		bm.bm.bmiHeader.biHeight		= -nCy; // '+': 显示时从下到上

		int byWidth = m_Size.cx * m_nBitCount/8;
		if( byWidth % 4 )
			byWidth = byWidth/4*4+4;
		INT_PTR nLength = ((INT_PTR)byWidth) * nCy;

		bm.bm.bmiHeader.biSizeImage		= (DWORD)nLength;
	}

	if( m_nBitCount != 32 )//		以备显示时有颜色
	{
		COLORREF cr;
		if( m_p8BitColors )
		{
			for(int i = 0; i < 255; i++)
			{
				cr = m_p8BitColors[i + 1];
				*((int *)(&bm.bmiColors[i])) = RGB_BGR(cr);
			}
		}
		else
		{
			COLORREF crs[] = {  RGB(255, 255, 255),
								RGB(192, 192, 192),
								RGB(128, 128, 128),
								RGB(255, 0, 0),
								RGB(128, 0, 0),
								RGB(0, 255, 0),
								RGB(0, 128, 0),
								RGB(0, 0, 255),
								RGB(0, 0, 128) };
			for(int i = 0; i < sizeof(crs)/sizeof(COLORREF); i++)
			{
				cr = crs[i];
				*((int *)(&bm.bmiColors[i])) = RGB_BGR(cr);
			}
		}
	}
}

// Bmp转DIB
BOOL CDibBase::CreateFromBmpFile(CString& sFileName)
{
	Destroy ();

	CFile file;
	if( !file.Open( sFileName, CFile::modeRead) )
		return false;
	
	BITMAPFILEHEADER bmiHeader;
	int nFileLen = (int)file.GetLength();
	
	// read file header
	if (file.Read( (LPSTR)&bmiHeader, sizeof(BITMAPFILEHEADER) ) != sizeof(BITMAPFILEHEADER) )
		return false;
	
	// file type should be 'bm'
	if (bmiHeader.bfType != ((WORD) ('M' << 8) | 'B')) 
		return false; 

	BITMAPINFO *pbminfo = (BITMAPINFO *)::GlobalAlloc(GMEM_FIXED, sizeof(BITMAPINFO) + sizeof(RGBQUAD)*256 ); 
	if ( !pbminfo ) 
		return FALSE; // read the bitmapinfo 
	file.Read( pbminfo, sizeof(BITMAPINFO) + sizeof(RGBQUAD)*256 ); 

	m_Size = CSize( pbminfo->bmiHeader.biWidth, abs(pbminfo->bmiHeader.biHeight) );
	m_nBitCount = pbminfo->bmiHeader.biBitCount;
	int byWidth = m_Size.cx * m_nBitCount/8;
	if( byWidth % 4 )
		byWidth = byWidth/4*4+4;
	m_nLength = ((INT_PTR)byWidth) * m_Size.cy;
	if( m_nBitCount == 8 )
	{
		if( !m_p8BitColors )
			m_p8BitColors = (COLORREF *)(new BYTE[ sizeof(COLORREF) * 256 ]);
		RGBQUAD cr;
		for(int i = 0; i < 256; i++)
		{
			cr = pbminfo->bmiColors[i];
			m_p8BitColors[i] = RGB(cr.rgbRed, cr.rgbGreen, cr.rgbBlue);
		}
	}

	BOOL bRet = false;
	if( DoCreate() )
	{
		LPBYTE lpdibbits; // pointer to dib bits 
		int nColors = pbminfo->bmiHeader.biClrUsed ? pbminfo->bmiHeader.biClrUsed : (1 << pbminfo->bmiHeader.biBitCount);// * sizeof(RGBQUAD); 
		if( pbminfo->bmiHeader.biBitCount > 8 )
			lpdibbits = (LPBYTE)((LPDWORD)(pbminfo->bmiColors + 
				pbminfo->bmiHeader.biClrUsed) + 
				((pbminfo->bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
		else
			lpdibbits = (LPBYTE)(pbminfo->bmiColors + nColors);

		int nOffset = (int)(sizeof(BITMAPFILEHEADER) + (lpdibbits - (LPBYTE)pbminfo));
		file.Seek( nOffset, CFile::begin);
#if _MSC_VER >= 1300
        file.Read( (LPSTR)m_pBits, fmin(m_nLength, nFileLen - nOffset)); //bminfo.bisizeimage );
#else
		file.ReadHuge( (LPSTR)m_pBits, min(m_nLength, nFileLen - nOffset)); //bminfo.bisizeimage ); 
#endif

		bRet = true;
	}

	::GlobalFree(pbminfo);

	return bRet;
}

#define RGB_BGR( color ) ((color >> 16) + (color & 0xff00) + ((color & 0xff) << 16))
#include ".\\ImageLib\\Jpeg.h"

BOOL CDibBase::SaveToJPGFile(CString sFileName, int nQuality)
{
	try
	{
		CFile file;
		if( !file.Open(sFileName, CFile::modeWrite | CFile::modeCreate) )
			return FALSE;

		if( !Jpeg_SaveToFile( &file, this, nQuality, NULL ) )
			return FALSE;
	}
	catch(CException* e)
	{
		e->Delete();
		return FALSE;
	}
	return TRUE;
}

BOOL CDibBase::CreateFromJPGFile(CString sFileName)
{
	CFile file;
	if( !file.Open(sFileName, CFile::modeRead) )
		return FALSE;

	m_bCreateFromJpg = true;
	if( !Jpeg_ReadFromFile( &file, 0, this ) )
		return FALSE;

	return true;
}

BOOL CDibBase::SaveToBmpFile(CString& sFileName)
{
	CFile file;
	if( !file.Open(sFileName, CFile::modeWrite | CFile::modeCreate) )
		return FALSE;

	//图形格式参数
	BYTE bSetColor = m_nBitCount == 8;
	int nInfoSize = sizeof(BITMAPINFOHEADER), bit = 1;
	if( bSetColor )
		nInfoSize += sizeof(RGBQUAD) * (bit << m_nBitCount);

	int nMemSize = sizeof(BITMAPINFO) - 4;
	if( bSetColor )
		nMemSize += sizeof(RGBQUAD) * ((bit << m_nBitCount));

	BITMAPINFO *lpbmih = (BITMAPINFO *)::GlobalAlloc(GMEM_FIXED, nMemSize );
	if( !lpbmih )
		return FALSE;

	int nRowByte = m_Size.cx * (m_nBitCount/8);
	int nFileRowByte = nRowByte;
	if( nFileRowByte % 4 )
		nFileRowByte = nFileRowByte/4*4+4;
	int biSizeImage = nFileRowByte* m_Size.cy;

	lpbmih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpbmih->bmiHeader.biWidth = m_Size.cx;
	lpbmih->bmiHeader.biHeight = m_Size.cy;
	lpbmih->bmiHeader.biPlanes = 1;
	lpbmih->bmiHeader.biBitCount = m_nBitCount;
	lpbmih->bmiHeader.biCompression = BI_RGB;
	lpbmih->bmiHeader.biSizeImage = biSizeImage;
	lpbmih->bmiHeader.biXPelsPerMeter = 0;
	lpbmih->bmiHeader.biYPelsPerMeter = 0;
	lpbmih->bmiHeader.biClrUsed = bSetColor ? ((1 << m_nBitCount)) : 0;
	lpbmih->bmiHeader.biClrImportant = 0;
	if( bSetColor && m_p8BitColors )
	{
		COLORREF cr;
		for(int i = 0; i < 256; i++)
		{
			cr = m_p8BitColors[i];
			*((int *)(&lpbmih->bmiColors[i])) = RGB_BGR(cr);
		}
	}

	//保存到文件并创建位图结构
	BITMAPFILEHEADER bmfh;
	ZeroMemory(&bmfh,sizeof(BITMAPFILEHEADER));
	*((char *)&bmfh.bfType) = 'B';
	*(((char *)&bmfh.bfType) + 1) = 'M';

	bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + nInfoSize;
	bmfh.bfSize = bmfh.bfOffBits + biSizeImage;
	
	file.Write(&bmfh, sizeof(BITMAPFILEHEADER));
	file.Write(&(lpbmih->bmiHeader), nMemSize);

	if( nFileRowByte == nRowByte )
		file.Write(m_pBits, biSizeImage);
	else
	{
		file.Write(m_pBits, nRowByte * m_Size.cy);
		BYTE aFills[100];
		memset(aFills, 0, 100);
		int nCount = biSizeImage - nRowByte * m_Size.cy;
		while(nCount > 0)
		{
            file.Write( aFills, fmin(100, nCount) );
			nCount -= 100;
		}
	}

	::GlobalFree(lpbmih);

	return TRUE;
}

// 将内容写入文件
BOOL CDibBase::SaveToFile(LPCTSTR lpFileName)
{
	if( m_nLength == 0 )
		return false;
	CFile file;
	if( file.Open(lpFileName, CFile::modeCreate|CFile::modeWrite) )
	{
        CString s((char*)_bstr_t("km_dib"));
		char sign[8];
		memset(sign, 0, 8);
		memcpy(sign, s.GetBuffer( s.GetLength() ), s.GetLength() );
		file.Write( sign, 8 );

		UINT size[2] = {m_Size.cx, m_Size.cy};
		file.Write(size, 8);
		file.Write(&m_nBitCount, 1);
		file.Write(&m_nLength, 4);
#if _MSC_VER >= 1300
		file.Write( m_pBits, (UINT)m_nLength );
#else
		file.WriteHuge( m_pBits, (UINT)m_nLength );
#endif

		return true;
	}
	return false;
}

BOOL CDibBase::SavePartToFile(LPCTSTR lpFileName, int nRowCount)
{
	if( m_nLength == 0 )
		return false;
	if( nRowCount <= 0 || nRowCount > m_Size.cy)
		return false;
	CFile file;
	if( file.Open(lpFileName, CFile::modeCreate|CFile::modeWrite|CFile::shareDenyRead) )
	{
        CString s((char*)_bstr_t("km_dib"));
		char sign[8];
		memset(sign, 0, 8);
		memcpy(sign, s.GetBuffer( s.GetLength() ), s.GetLength() );
		file.Write( sign, 8 );

		UINT size[2] = {m_Size.cx, nRowCount};
		file.Write(size, 8);
		file.Write(&m_nBitCount, 1);

		INT_PTR nLength = nRowCount * m_Size.cx * (m_nBitCount/8);
		file.Write(&nLength, 4);
#if _MSC_VER >= 1300
		file.Write( m_pBits, (UINT)nLength );
#else
		file.WriteHuge( m_pBits, (UINT)nLength );
#endif

		return true;
	}
	return false;
}

BOOL CDibBase::SavePartToFile2(LPCTSTR lpFileName, LPCTSTR lpFileName2, LPCTSTR lpFileName3, LPCTSTR lpFileName4, int nRowCount, int nSectionRowCount)
{
	if( m_nLength == 0 )
		return false;
	if( nRowCount <= 0 )
		return false;
	if( nRowCount > m_Size.cy )
		nRowCount = m_Size.cy;

	const int nFileCount = 4;
	memset(m_bFinishs, 0, nFileCount);

	CString aFileNames[ nFileCount - 1 ] = {lpFileName2, lpFileName3, lpFileName4};
	for(int iFile = 1; iFile < nFileCount; iFile++)
	{
		THREAD_SAVE_PARA* pPara = new THREAD_SAVE_PARA;
		pPara->iFile = iFile;
		pPara->sFileName = aFileNames[ iFile - 1 ];
		pPara->nSectionRowCount = nSectionRowCount;
		pPara->nTotalRowCount = nRowCount;
		pPara->pThis = this;
		AfxBeginThread( ThreadSavePartToFile2, pPara );
	}
    CString lpfn(lpFileName);
    DoSavePartToFile2( lpfn, nSectionRowCount, 0, nRowCount );

	// 等待所有线程读完
	while(1)
	{
		if(	m_bFinishs[1] && m_bFinishs[2] && m_bFinishs[3] )
			break;
		Sleep(30);
	}

	return true;
}

UINT CDibBase::ThreadSavePartToFile2(LPVOID lpPara)
{
	THREAD_SAVE_PARA* pPara = (THREAD_SAVE_PARA *)lpPara;

	pPara->pThis->DoSavePartToFile2( pPara->sFileName, pPara->nSectionRowCount, pPara->iFile, pPara->nTotalRowCount );
	pPara->pThis->m_bFinishs[ pPara->iFile ] = 1;

	delete pPara;
	return 0;
}

BOOL CDibBase::DoSavePartToFile2(CString& sFileName, int nSectionRowCount, int iFile, int nTotalRowCount)
{
	try
	{
		if( Do_DoSavePartToFile2(sFileName, nSectionRowCount, iFile, nTotalRowCount) )
			return true;
	}
	catch( CException* e )
	{
		e->Delete();
	}
	return false;
}

BOOL CDibBase::Do_DoSavePartToFile2(CString& sFileName, int nSectionRowCount, int iFile, int nTotalRowCount)
{
	CFile file;
	BOOL bSuc = false;
	for(int iTime = 0; iTime < 10; iTime++)
	{
		if( file.Open(sFileName, CFile::modeCreate|CFile::modeWrite|CFile::shareDenyRead) )
		{
			bSuc = true;
			break;
		}
		Sleep(10);
	}
	if( !bSuc )
		return false;

	// 标志
    CString s((char*)_bstr_t("im_dib"));
	char sign[8];
	memset(sign, 0, 8);
	memcpy(sign, s.GetBuffer( s.GetLength() ), s.GetLength() );
	file.Write( sign, 8 );

	char nFileIndex = iFile;
	file.Write( &nFileIndex, 1 );

	// 尺寸
	UINT size[2] = {m_Size.cx, nTotalRowCount};
	file.Write(size, 8);
	file.Write(&m_nBitCount, 1);

	// 段
	file.Write( &nSectionRowCount, 2 );

	int nSectionCount = nTotalRowCount/nSectionRowCount;
	int nRestRowCount = nTotalRowCount % nSectionRowCount;
	if( nRestRowCount )
		nSectionCount++;
	const int nFileCount = 4;
	BYTE* pBit = (BYTE *)m_pBits;
	int nRowLen = m_Size.cx * (m_nBitCount/8);
	int nSectionLen = nSectionRowCount * nRowLen;
	pBit += (iFile * nSectionLen);
	int nBitOffset = nFileCount * nSectionLen;
	for(int iSection = iFile; iSection < nSectionCount; iSection += nFileCount)
	{
		if( iSection == nSectionCount - 1 && nRestRowCount )
		{
			file.Write( pBit, nRestRowCount * nRowLen );
		}
		else
		{
			file.Write( pBit, nSectionLen );
		}
		pBit += nBitOffset;
	}

	return true;
}

BOOL CDibBase::LoadFromFile2(LPCTSTR lpFileName, LPCTSTR lpFileName2, LPCTSTR lpFileName3, LPCTSTR lpFileName4, LOAD_PROGRESS_CALLBACK lpCallback, LPVOID lpPara, int nBeginRow)
{
	// 打开文件
	CFile file;
	BOOL bSuc = false;
	for(int iTime = 0; iTime < 10; iTime++)
	{
		if( file.Open(lpFileName, CFile::modeRead) )
		{
			bSuc = true;
			break;
		}
		Sleep(10);
	}
	if( !bSuc )
		return false;

	// 读标志
	char sign[8];
	file.Read( sign, 8 );
    CString s((char*)_bstr_t(sign));
	if( s != "im_dib" )
		return false;
	char nFileIndex = 0;
	file.Read( &nFileIndex, 1 );
	if( nFileIndex != 0 )
		return false;

	// 读尺寸
	UINT size[2];
	int nBitCount = 0;
	file.Read( size, 8 );
	file.Read( &nBitCount, 1 );
	if( !(size[ 0 ] > 0 && size[ 1 ] > 0 && 
		  nBitCount > 0 && nBitCount < 33 ) )
		return false;
	int nTotalRowCount = size[1];

	// 读段
	int nSectionRowCount = 0;
	file.Read( &nSectionRowCount, 2 );
	if( nSectionRowCount < 1 || nSectionRowCount > 200000 )
		return false;

	// 创建DIB
	if( nBeginRow > 0 )
		size[1] -= nBeginRow;
	CSize sz(size[0], size[1]);
	if( m_Size != CSize(0, 0) ) // 按指定尺寸加载
	{
		if( m_Size.cx != sz.cx || nBitCount != m_nBitCount ) // 横向必须相同
			return false;
	}
	else
	{
		if( !Create(sz.cx, sz.cy, nBitCount) )
			return false;
	}

	// 开始读
	const int nFileCount = 4;
	int nReadTimeCount = nTotalRowCount / (nSectionRowCount * nFileCount);
	if( nTotalRowCount % (nSectionRowCount * nFileCount) )
		nReadTimeCount++;
	m_aFinishSections = new BYTE[ nReadTimeCount * nFileCount ];
	memset( m_aFinishSections, 0, nReadTimeCount * nFileCount );
	m_iFinishSection = -1;

	memset(m_bFinishs, 0, nFileCount);

	CString aFileNames[ nFileCount - 1 ] = {lpFileName2, lpFileName3, lpFileName4};
	for(int iFile = 1; iFile < nFileCount; iFile++)
	{
		THREAD_LOAD_PARA* pPara = new THREAD_LOAD_PARA;
		pPara->iFile = iFile;
		pPara->sFileName = aFileNames[ iFile - 1 ];
		pPara->nSectionRowCount = nSectionRowCount;
		pPara->nTotalRowCount = nTotalRowCount;
		pPara->nBeginRow = nBeginRow;
		pPara->lpCallback = lpCallback;
		pPara->lpPara = lpPara;
		pPara->pThis = this;
		AfxBeginThread( ThreadLoadFromFile2, pPara );
	}

	DoLoadFromFile2(file, nSectionRowCount, 0, nTotalRowCount, lpCallback, lpPara, nBeginRow);

	// 等待所有线程读完
	while(1)
	{
		if(	m_bFinishs[1] && m_bFinishs[2] && m_bFinishs[3] )
			break;
		Sleep(30);
	}
	delete[] m_aFinishSections;

	return true;
}

UINT CDibBase::ThreadLoadFromFile2(LPVOID lpPara)
{
	THREAD_LOAD_PARA* pPara = (THREAD_LOAD_PARA *)lpPara;

	CFile file;
	BOOL bSuc = false;
	for(int iTime = 0; iTime < 10; iTime++)
	{
		if( file.Open(pPara->sFileName, CFile::modeRead) )
		{
			bSuc = true;
			break;
		}
		Sleep(10);
	}
	if( bSuc )
	{
		pPara->pThis->DoLoadFromFile2( file, pPara->nSectionRowCount, pPara->iFile, pPara->nTotalRowCount, pPara->lpCallback, pPara->lpPara, pPara->nBeginRow );
	}

	pPara->pThis->m_bFinishs[ pPara->iFile ] = 1;
	delete pPara;
	return 0;
}

BOOL CDibBase::DoLoadFromFile2(CFile& file, int nSectionRowCount, int iFile, int nTotalRowCount, LOAD_PROGRESS_CALLBACK lpCallback, LPVOID lpPara, int nBeginRow)
{
	if( iFile > 0 )
	{
		// 读标志
		char sign[8];
		file.Read( sign, 8 );
        CString s((char*)_bstr_t(sign));
		if( s != "im_dib" )
			return false;
		char nFileIndex = 0;
		file.Read( &nFileIndex, 1 );
		if( nFileIndex != iFile )
			return false;

		// 读尺寸
		UINT size[2];
		int nBitCount = 0;
		file.Read( size, 8 );
		file.Read( &nBitCount, 1 );
		if( size[0] != m_Size.cx || size[1] != nTotalRowCount || nBitCount != m_nBitCount )
			return false;

		// 读段
		int nRead = 0;
		file.Read( &nRead, 2 );
		if( nRead != nSectionRowCount )
			return false;
	}

	const int nFileCount = 4;
	int nReadTimeCount = nTotalRowCount / (nSectionRowCount * nFileCount);
	if( nTotalRowCount % (nSectionRowCount * nFileCount) )
		nReadTimeCount++;
	int nRowLen = m_Size.cx * (m_nBitCount/8);
	INT_PTR nSectionLen = nSectionRowCount * nRowLen;

	if( nBeginRow < 0 || nBeginRow > nSectionRowCount )
		nBeginRow = 0;

	int nCurRow = iFile * nSectionRowCount;
	if( iFile && nBeginRow )
		nCurRow -= nBeginRow;
	nTotalRowCount -= nBeginRow;
	if( nTotalRowCount > m_Size.cy )
		nTotalRowCount = m_Size.cy;
	int nSignCount = nReadTimeCount * nFileCount, i, b, nFinishRow;

	BYTE* pBit = ((BYTE *)m_pBits) + nCurRow * nRowLen;
	int nMaxReadRowCount, nReadRow, nOffsetRow = nSectionRowCount * (nFileCount - 1);
	for(int iTime = 0; iTime < nReadTimeCount; iTime++)
	{
		nReadRow = nSectionRowCount;
		if( iTime == 0 && iFile == 0 && nBeginRow )
		{
			INT_PTR nSeek = ((INT_PTR)nBeginRow) * nRowLen;
			file.Seek(nSeek, CFile::current);
			nReadRow -= nBeginRow;
		}

        nMaxReadRowCount = fmin(nTotalRowCount - nCurRow, nSectionRowCount);
		if( nReadRow > nMaxReadRowCount )
			nReadRow = nMaxReadRowCount;
		if( nReadRow <= 0 )
			break;

		file.Read( pBit, nReadRow * nRowLen );
		pBit += ((nReadRow + nOffsetRow) * nRowLen);
		TRACE3("%d: %d-%d\n", iFile, nCurRow, nCurRow + nReadRow);
		nCurRow += (nReadRow + nOffsetRow);
		if( m_mutex.Lock() )
		{
			TRACE2("%d: %d\n", iFile, iTime * nFileCount + iFile);
			m_aFinishSections[ iTime * nFileCount + iFile ] = 1;
			b = m_iFinishSection;
			for(i = m_iFinishSection + 1; i < nSignCount; i++)
			{
				if( !m_aFinishSections[ i ] )
				{
					m_iFinishSection = i - 1;
					if( m_iFinishSection != b )
					{
						if( lpCallback )
						{
							nFinishRow = (m_iFinishSection + 1) * nSectionRowCount - nBeginRow - 1;
							if( nFinishRow >= nTotalRowCount )
								nFinishRow = nTotalRowCount - 1;
							(*lpCallback)(lpPara, nFinishRow);

							TRACE1("%d: ", nFinishRow);
							for(int j = 0; j < nSignCount; j++)
								TRACE1("%d, ", m_aFinishSections[ j ]);
							TRACE0("\n");
						}
					}
					break;
				}
			}
			m_mutex.Unlock();
		}
	}

	return true;
}

BOOL CDibBase::Serialize(CArchive& ar)
{
	UINT nCurVersion = 2, nVersionLoad;
	ar >> nVersionLoad;
	//if( !IBaseTool::Serialize_Version(ar, nCurVersion, nVersionLoad) )
	if( nCurVersion != nVersionLoad )
		return FALSE;

	if( ar.IsLoading() )
	{
		Destroy();

		ar >> m_Size;
		ar >> m_nBitCount;

		INT_PTR nLength;
		if( nVersionLoad < 2 )
		{
			int l;
			ar >> l;
			nLength = l;
		}
		else
		{
			ar >> nLength;
		}

		if( nVersionLoad > 0 )
		{
			BYTE bSign;
			ar >> bSign;
			if( bSign )
			{
				m_p8BitColors = (COLORREF *)(new BYTE[ sizeof(COLORREF) * 256 ]);
				ar.Read( m_p8BitColors, 256 * sizeof(COLORREF) );
			}
		}

		if( m_Size.cx > 0 && m_Size.cy > 0 )
		{
			if( m_nBitCount < 1 || m_nBitCount > 32 )
				return false;

			if( RecLen(m_Size.cx, m_Size.cy, m_nBitCount) != nLength )
				return false;
			if( !Create(m_Size.cx, m_Size.cy, m_nBitCount) )
				return false;
			ar.Read( m_pBits, (UINT)m_nLength );
		}
	}
	else
	{
		ar << m_Size;
		ar << m_nBitCount;
		ar << m_nLength;

		BYTE bSign = (m_nBitCount == 8 && m_p8BitColors) ? 1 : 0;
		ar << bSign;
		if( bSign )
			ar.Write( m_p8BitColors, 256 * sizeof(COLORREF) );

		if( m_Size.cx > 0 && m_Size.cy > 0 )
		{
			ASSERT( m_pBits != NULL && m_nLength > 0 );
			ar.Write( m_pBits, (UINT)m_nLength );
		}
	}
	return TRUE;
}

BOOL CDibBase::Copy(IDib* pSrc)
{
	Destroy();

	CDibBase& src = *(CDibBase *)pSrc;
	m_Size = src.m_Size;
	m_nBitCount = src.m_nBitCount;

	if( src.m_p8BitColors )
	{
		m_p8BitColors = (COLORREF *)(new BYTE[ sizeof(COLORREF) * 256 ]);
		memcpy( m_p8BitColors, src.m_p8BitColors, 256 * sizeof(COLORREF) );
	}

	if( m_Size.cx > 0 && m_Size.cy > 0 )
	{
		if( !Create(m_Size.cx, m_Size.cy, m_nBitCount) )
			return false;
		memcpy( m_pBits, src.m_pBits, (UINT)m_nLength );
	}
	return true;
}

#include <iostream>
using namespace std;

#define LOG()  cout << __LINE__ << " " << __FUNCTION__ << " " << "::"

BOOL CDibBase::SerializeJpg(CArchive& ar)
{
	UINT nCurVersion = 1, nVersionLoad;
	ar >> nVersionLoad;
	//LOG() << "nVersionLoad " << nVersionLoad << endl;
	//if( !IBaseTool::Serialize_Version(ar, nCurVersion, nVersionLoad) )
	if( nCurVersion != nVersionLoad )
		return FALSE;

	BYTE bCompress;
	int nLen = 0;
	//LOG() << "ar.IsLoading() " << ar.IsLoading() << endl;
	if( ar.IsLoading() )
	{
		if( nVersionLoad > 0 )
			ar >> bCompress;
		else
			bCompress = true;
		
		//LOG() << "bCompress " << (bool)bCompress << endl;
		if( bCompress )
		{
			ar >> nLen;
			//LOG() << "nLen " << nLen << endl;
			ar.Flush();
	
			if( !Jpeg_ReadFromFile( ar.GetFile(), nLen, this ) )
				return FALSE;
		}
		else
		{
			if( !Serialize(ar) )
				return false;
		}
	}
	else
	{
		int qua = GetJpgQuality();
		
		bCompress = (qua < 100);
		ar << bCompress;

		if( bCompress )
		{
			if( !Jpeg_SaveToFile( NULL, this, qua, &nLen ) )
				return FALSE;

			ar << nLen;
			ar.Flush();

			if( !Jpeg_SaveToFile( ar.GetFile(), this, qua, NULL ) )
				return FALSE;
		}
		else
		{
			if( !Serialize(ar) )
				return false;
		}
	}
	return TRUE;
}

//#include <stdlib.h>
//#include <stdio.h>
int CDibBase::GetJpgQuality()
{
    return 100;
//    CString sFileName((char*)_bstr_t(".\\jpgquality"));
//	//CString sFileName = IBaseTool::GetAppPath() + "\\jpgquality";
//	CStdioFile file;
//	if( file.Open( sFileName, CFile::modeRead ) )
//	{
//		CString text;
//		if( file.ReadString( text ) )
//		{
//            int i = atoi(text.GetString());
//			if( i > 0 && i <= 100 )
//				return i;
//		}
//	}
	return 85;
}

BOOL CDibBase::LoadFromFile(LPCTSTR lpFileName)
{
//return CreateFromBmpFile( CString(lpFileName) );
	CFile file;
	if( !file.Open(lpFileName, CFile::modeRead) )
		return false;
	return LoadFromFile(file);
}

BOOL CDibBase::LoadFromFile(CFile& file, int nRowCountPerTime, LOAD_PROGRESS_CALLBACK lpCallback, LPVOID lpPara, int nBeginRow)
{
	UINT size[2];
	int nBitCount = 0;
	INT_PTR nLength = 0;

	char sign[8];
	file.Read( sign, 8 );
    CString s((char*)_bstr_t(sign));
	if( s != "km_dib" )
		return false;

	file.Read( size, 8 );
	file.Read( &nBitCount, 1 );
	file.Read( &nLength, 4 );

//	nBitCount = 32;
//	nLength = size[0] * size[1] * sizeof(int);

	if( !(size[ 0 ] > 0 && size[ 1 ] > 0 && 
		  nBitCount > 0 && nBitCount < 33 && 
		  nLength > 0) )
		return false;

	if( nBeginRow > 0 )
	{
		INT_PTR nSeek = ((INT_PTR)nBeginRow) * size[0] * (nBitCount/8);
		file.Seek(nSeek, CFile::current);
		nLength -= nSeek;
		size[1] -= nBeginRow;
	}

	CSize sz(size[0], size[1]);
	if( m_Size != CSize(0, 0) ) // 按指定尺寸加载
	{
		if( m_Size.cx != sz.cx || nBitCount != m_nBitCount ) // 横向必须相同
			return false;
		if( nLength > m_nLength ) // 文件图像过大，截掉
			nLength = m_nLength;
	}
	else
	{
		if( !Create(sz.cx, sz.cy, nBitCount) )
			return false;
		if( m_nLength != nLength )
			return false;
	}

	if( nRowCountPerTime > 0 )
	{
		UINT nLenStep = m_Size.cx * nRowCountPerTime * (m_nBitCount/8);
		BYTE* pBit = (BYTE *)m_pBits;

		int nRow = 0;
		while(nLength > 0)
		{
			if( nLenStep > nLength )
				nLenStep = nLength;

		#if _MSC_VER >= 1300
			file.Read( pBit, nLenStep );
		#else
			file.ReadHuge( pBit, nLenStep );
		#endif

			pBit += nLenStep;
			nLength -= nLenStep;

			nRow += nRowCountPerTime;
			if( nRow > m_Size.cy )
				nRow = m_Size.cy;
			if( lpCallback )
				(*lpCallback)(lpPara, nRow);
		}
	}
	else
	{
	#if _MSC_VER >= 1300
		file.Read( m_pBits, (UINT)nLength );
	#else
		file.ReadHuge( m_pBits, (UINT)nLength );
	#endif
	}
	return true;
}

// 销毁
void CDibBase::Destroy ()
{
	m_nLength = 0;
	m_nBitCount = 0;
	m_Size = CSize( 0, 0 );
	if( m_pBufBits )
	{
		delete[] m_pBufBits;
		m_pBufBits = NULL;
	}
}

// 填
void CDibBase::FillContent( int iValue )
{
	if( m_pBits )
	{
		if( iValue == 0 )
			ZeroMemory( m_pBits, m_nLength );
		else if( iValue == -1 )
			FillMemory( m_pBits, m_nLength, 0xff );
		else
		{
			if( m_nBitCount < 32 )
			{
				int lBak = iValue;
				for(int i = m_nBitCount; i < 32; i += m_nBitCount)
					iValue = (iValue << m_nBitCount) | iValue;
			}

			INT_PTR n = m_nLength / 4;
			int* pBits = (int *)m_pBits;
			for(int i = 0; i < n; i++, pBits++)
				*pBits = iValue;
		}
	}
}

void CDibBase::Mirror(BOOL bMirrorX, BOOL bMirrorY)
{
	int cb;
	if( m_nBitCount == 32 )
		cb = 4;
	else if( m_nBitCount == 24 )
		cb = 3;
	else  if( m_nBitCount == 8 )
		cb = 1;
	else
		return;

	int cx = (int)m_Size.cx;
	int cy = (int)m_Size.cy;
	if( bMirrorY )
	{
		int cxl = cx * cb;
		if( cxl % 4 )
			cxl = cxl/4*4+4;

		BYTE* pBuf = new BYTE[ cxl ];
		BYTE* pBit1 = (BYTE *)m_pBits;
		BYTE* pBit2 = pBit1 + (cy - 1) * ((INT_PTR)cxl);
		for(int y1 = 0, y2 = cy - 1; y1 < y2; y1++, y2--)
		{
			memcpy(pBuf, pBit1, cxl);
			memcpy(pBit1, pBit2, cxl);
			memcpy(pBit2, pBuf, cxl);

			pBit1 += cxl;
			pBit2 -= cxl;
		}
		delete[] pBuf;
	}
}

//////////////////////////////////////////////////////////////////////////////////
//

template<class T>
void ContourDib(T* pBits, T* pDestBits, CSize& size, T valueBk)
{
	int cxDib = (int)size.cx;
	int cyDib = (int)size.cy;
	int cxDibMinus = cxDib - 1;
	int cyDibMinus = cyDib - 1;

	pBits += cxDib;
	pDestBits += cxDib;
	for(int y = 1; y < cyDibMinus; y++)
	{
		pBits++; // from col 1
		pDestBits++;
		for(int x = 1; x < cxDibMinus; x++, pBits++, pDestBits++)
		{
			if( *pBits &&
				*(pBits - 1) &&		// left
				*(pBits + 1) &&		// right
				*(pBits - cxDib) &&	// up
				*(pBits + cxDib) )   // down
			{
				*pDestBits = valueBk;
			}
		}
		pBits++; // end col
		pDestBits++;
	}
}

// 轮廓提取
BOOL CDibBase::Contour()
{
	if( m_nLength == 0 )
		return false;

	MallocBufBits();
	memcpy(m_pBufBits, m_pBits, m_nLength);

	BOOL bRet = true;
	if( m_nBitCount == 32 )
		ContourDib<int>( (int *)m_pBufBits, (int *)m_pBits, m_Size, 0 );
	else if( m_nBitCount == 16 )
		ContourDib<WORD>( (WORD *)m_pBufBits, (WORD *)m_pBits, m_Size, 0 );
	else if( m_nBitCount == 8 )
		ContourDib<char>( (char *)m_pBufBits, (char *)m_pBits, m_Size, 0 );
	else
		bRet = false; 

	return bRet;
}

// 腐蚀
BOOL CDibBase::Erosion(BYTE* pS, int sl, void* pCopyToBits, IProgressBar* pBar)
{
	if( m_nBitCount != 32 &&
		m_nBitCount != 8 )
		return false;

	BOOL bMemcpy = false;
	if( !pCopyToBits )
	{
		if( !MallocBufBits() )
			return false;
		pCopyToBits = m_pBufBits;
		bMemcpy = true;
	}

	if( m_nBitCount == 32 )
		DoErosion32(pS, sl, (int *)m_pBits, (int *)pCopyToBits, m_Size);
	else
		DoErosion8(pS, sl, (BYTE *)m_pBits, (BYTE *)pCopyToBits, m_Size, pBar);

	if( bMemcpy )
		memcpy( m_pBits, pCopyToBits, m_nLength );

	return true;
}

bool CDibBase::MallocBufBits()
{
	if( !m_pBufBits )
	{
		m_pBufBits = new BYTE[ m_nLength ];
		if( !m_pBufBits )
			return false;
	}
	ZeroMemory( m_pBufBits, m_nLength );

	return true;
}

void CDibBase::DoErosion32(BYTE* pS, int sl, int* pSrcBits, int* pDestBits, CSize Size)
{
	int halfSl = sl/2, offset;
	BYTE* pS2;
	bool bSet;
	int cx = Size.cx - halfSl, cy = Size.cy - halfSl;
	int lWidth = Size.cx;
	int* pSrcBit = pSrcBits + halfSl * lWidth, *pSrcBit2;
	int* pDestBit = pDestBits + halfSl * lWidth;
	for(int y = halfSl; y < cy; y++)
	{
		pSrcBit += halfSl;
		pDestBit += halfSl;
		for(int x = halfSl; x < cx; x++, pDestBit++, pSrcBit++)
		{
			if( *pSrcBit == 0 )
				continue;
			offset = halfSl + lWidth * halfSl;
			pSrcBit2 = pSrcBit - offset;
			bSet = true;
			pS2 = pS;
			offset = lWidth - sl;
			for(int j = 0; j < sl; j++)
			{
				for(int i = 0; i < sl; i++, pSrcBit2++, pS2++)
				{
					if( *pS2 )
					{
						if( *pSrcBit2 == 0 )
						{
							bSet = false;
							j = sl;
							break;
						}
					}
				}
				pSrcBit2 += offset;
			}
			if( bSet )
				*pDestBit = 1;
		}
		pSrcBit += halfSl;
		pDestBit += halfSl;
	}
}
void CDibBase::DoErosion8(BYTE* pS, int sl, BYTE* pSrcBits, BYTE* pDestBits, CSize Size, IProgressBar* pBar)
{
	int halfSl = sl/2, halfSlr = halfSl * Size.cx;
	int halfSl2 = halfSl/2, halfSlr2 = halfSlr/2;
	int lWidth = Size.cx;
	int offset0 = halfSl + lWidth * halfSl;
	int offset2 = lWidth - sl;
	int cx = Size.cx - halfSl, cy = Size.cy - halfSl;
	BYTE* pSrcBit = pSrcBits + halfSl * lWidth, *pSrcBit2;
	BYTE* pDestBit = pDestBits + halfSl * lWidth;

	int nStep = 0, nStepCount = (cy - halfSl)/100;
	//if( pBar )pBar->SetPos(0);

	BYTE* pS2;
	bool bSet;
	for(int y = halfSl; y < cy; y++)
	{
		pSrcBit += halfSl;
		pDestBit += halfSl;
		for(int x = halfSl; x < cx; x++, pDestBit++, pSrcBit++)
		{
			if( *pSrcBit == 0 )
				continue;

			// 粗略看
			if( *(pSrcBit - halfSl) == 0 ||
				*(pSrcBit + halfSl) == 0 ||
				*(pSrcBit - halfSlr) == 0 ||
				*(pSrcBit + halfSlr) == 0 ||
				*(pSrcBit - halfSl2) == 0 ||
				*(pSrcBit + halfSl2) == 0 ||
				*(pSrcBit - halfSlr2) == 0 ||
				*(pSrcBit + halfSlr2) == 0 )
				continue;

			// 详细看
			pSrcBit2 = pSrcBit - offset0;
			bSet = true;
			pS2 = pS;
			for(int j = 0; j < sl; j++)
			{
				for(int i = 0; i < sl; i++, pSrcBit2++, pS2++)
				{
					if( *pS2 && *pSrcBit2 == 0 )
					{
						bSet = false;
						j = sl;
						break;
					}
				}
				pSrcBit2 += offset2;
			}
			if( bSet )
				*pDestBit = 1;
		}
		pSrcBit += halfSl;
		pDestBit += halfSl;
//		if( pBar ){ if( ++nStep > nStepCount ){ nStep = 0; pBar->StepIt(); } }
	}
}

// 膨胀
BOOL CDibBase::Dilation(BYTE* pS, int sl)
{
	if( m_nBitCount != 32 )
		return false;

	if( !MallocBufBits() )
		return false;

	DoDilation(pS, sl, (int *)m_pBits, (int *)m_pBufBits, m_Size);
	memcpy( m_pBits, m_pBufBits, m_nLength );

	return true;
}

void CDibBase::DoDilation(BYTE* pS, int sl, int* pSrcBits, int* pDestBits, CSize Size)
{
	int halfSl = sl/2, offset;
	BYTE* pS2;
	bool bSet;
	int cx = Size.cx - halfSl, cy = Size.cy - halfSl;
	int lWidth = Size.cx;
	int* pSrcBit = pSrcBits + halfSl * lWidth, *pSrcBit2;
	int* pDestBit = pDestBits + halfSl * lWidth;
	for(int y = halfSl; y < cy; y++)
	{
		pSrcBit += halfSl;
		pDestBit += halfSl;
		for(int x = halfSl; x < cx; x++, pDestBit++, pSrcBit++)
		{
			offset = halfSl + lWidth * halfSl;
			pSrcBit2 = pSrcBit - offset;
			bSet = false;
			pS2 = pS;
			offset = lWidth - sl;
			for(int j = 0; j < sl; j++)
			{
				for(int i = 0; i < sl; i++, pSrcBit2++, pS2++)
				{
					if( *pS2 )
					{
						if( *pSrcBit2 )
						{
							bSet = true;
							j = sl;
							break;
						}
					}
				}
				pSrcBit2 += offset;
			}
			if( bSet )
				*pDestBit = 1;
		}
		pSrcBit += halfSl;
		pDestBit += halfSl;
	}
}

// 开计算
BOOL CDibBase::Open(BYTE* pS, int sl)
{
	if( m_nBitCount != 32 )
		return false;
	if( !MallocBufBits() )
		return false;

	DoErosion32(pS, sl, (int *)m_pBits, (int *)m_pBufBits, m_Size);
	ZeroMemory( m_pBits, m_nLength );
	DoDilation(pS, sl, (int *)m_pBufBits, (int *)m_pBits, m_Size);

	return true;
}

// 闭计算
BOOL CDibBase::Close(BYTE* pS, int sl)
{
	if( m_nBitCount != 32 )
		return false;
	if( !MallocBufBits() )
		return false;

	DoDilation(pS, sl, (int *)m_pBits, (int *)m_pBufBits, m_Size);
	ZeroMemory( m_pBits, m_nLength );
	DoErosion32(pS, sl, (int *)m_pBufBits, (int *)m_pBits, m_Size);

	return true;
}

void CDibBase::Homochromize(int value)
{
	int* pBit = (int *)m_pBits;
	int cx = m_Size.cx, cy = m_Size.cy;
	for(int y = 0; y < cy; y++)
	{
		for(int x = 0; x < cx; x++, pBit++)
		{
			if( *pBit != 0 )
				*pBit = value;
		}
	}
}

#include "mmsystem.h"

// 细化

BOOL CDibBase::Thining()
{
	if( m_nBitCount != 32 )
		return false;

//DWORD t = timeGetTime();

	// 初始化新分配的内存
	if( !MallocBufBits() )
		return false;
	Homochromize(); // 二值化
	
	int neighbour[4][4];   //5×5相邻区域像素值
	int i, j, m, n;
	int* lpSrc, *lpDst, *lpSrc2, *lpDst2;
	int nCount;
	bool bModified;
	int nTime = 0, iCount = m_Size.cx - 2, jCount = m_Size.cy - 2, lWidth = m_Size.cx;
	do
	{
		bModified = FALSE;

		if( ++nTime % 2 == 1 )
		{
			lpSrc = (int *)m_pBits;
			lpDst = (int *)m_pBufBits;
		}
		else
		{
			lpSrc = (int *)m_pBufBits;
			lpDst = (int *)m_pBits;
		}
		if( nTime > 1 )
			ZeroMemory( lpDst, m_Size.cx * m_Size.cy * sizeof(int) );

		lpSrc += 2 * lWidth;
		lpDst += 2 * lWidth;
		for(j = 2; j < jCount; j++)
		{
			lpSrc += 2;
			lpDst += 2;
			for(i = 2; i < iCount; i++, lpSrc++, lpDst++)
			{
				if( *lpSrc == 0 )
					continue;

				//获得当前点相邻的5×5区域内像素值，白色用0代表，黑色用1代表
				lpSrc2 = lpSrc - 2 * lWidth - 2;
				lpDst2 = (int *)neighbour;
				for (m = 0; m < 4; m++)
				{
					for (n = 0; n < 4; n++, lpSrc2++, lpDst2++)
						*lpDst2 = *lpSrc2;
					lpSrc2 += lWidth - 4;
				}

				//逐个判断条件。
				//判断2<=NZ(P1)<=6
				nCount =  neighbour[1][1] + neighbour[1][2] + neighbour[1][3] \
						+ neighbour[2][1] + neighbour[2][3] + \
						+ neighbour[3][1] + neighbour[3][2] + neighbour[3][3];
				if(nCount < 2 || nCount > 6)
				{
					*lpDst = 1;
					continue;
				}

				//判断Z0(P1)=1
				nCount = 0;
				if (neighbour[1][2] == 0 && neighbour[1][1] == 1)
					nCount++;
				if (neighbour[1][1] == 0 && neighbour[2][1] == 1)
					nCount++;
				if (neighbour[2][1] == 0 && neighbour[3][1] == 1)
					nCount++;
				if (neighbour[3][1] == 0 && neighbour[3][2] == 1)
					nCount++;
				if (neighbour[3][2] == 0 && neighbour[3][3] == 1)
					nCount++;
				if (neighbour[3][3] == 0 && neighbour[2][3] == 1)
					nCount++;
				if (neighbour[2][3] == 0 && neighbour[1][3] == 1)
					nCount++;
				if (neighbour[1][3] == 0 && neighbour[1][2] == 1)
					nCount++;
				if (nCount != 1)
				{
					*lpDst = 1;
					continue;
				}

				//判断P2*P4*P8=0 or Z0(p2)!=1
				if( neighbour[1][2] * neighbour[2][1] * neighbour[2][3] )
				{
					nCount = 0;
					if (neighbour[0][2] == 0 && neighbour[0][1] == 1)
						nCount++;
					if (neighbour[0][1] == 0 && neighbour[1][1] == 1)
						nCount++;
					if (neighbour[1][1] == 0 && neighbour[2][1] == 1)
						nCount++;
					if (neighbour[2][1] == 0 && neighbour[2][2] == 1)
						nCount++;
					if (neighbour[2][2] == 0 && neighbour[2][3] == 1)
						nCount++;
					if (neighbour[2][3] == 0 && neighbour[1][3] == 1)
						nCount++;
					if (neighbour[1][3] == 0 && neighbour[0][3] == 1)
						nCount++;
					if (neighbour[0][3] == 0 && neighbour[0][2] == 1)
						nCount++;
					if (nCount == 1)
					{
						*lpDst = 1;
						continue;
					}
				}

				//判断P2*P4*P6=0 or Z0(p4)!=1
				if( neighbour[1][2] * neighbour[2][1] * neighbour[3][2] )
				{
					nCount = 0;
					if (neighbour[1][1] == 0 && neighbour[1][0] == 1)
						nCount++;
					if (neighbour[1][0] == 0 && neighbour[2][0] == 1)
						nCount++;
					if (neighbour[2][0] == 0 && neighbour[3][0] == 1)
						nCount++;
					if (neighbour[3][0] == 0 && neighbour[3][1] == 1)
						nCount++;
					if (neighbour[3][1] == 0 && neighbour[3][2] == 1)
						nCount++;
					if (neighbour[3][2] == 0 && neighbour[2][2] == 1)
						nCount++;
					if (neighbour[2][2] == 0 && neighbour[1][2] == 1)
						nCount++;
					if (neighbour[1][2] == 0 && neighbour[1][1] == 1)
						nCount++;
					if (nCount == 1)
					{
						*lpDst = 1;
						continue;
					}
				}
				bModified = TRUE; // 删除
			}
			lpSrc += 2;
			lpDst += 2;
		}
	}while(bModified);
	
	// 复制腐蚀后的图像
	if( nTime % 2 == 1 )
		memcpy(m_pBits, m_pBufBits, m_nLength );

	Homochromize(255); // 二值化
/*
CString text;
text.Format("%d", timeGetTime() - t);
AfxMessageBox(text);
*/
	// 返回
	return true;
}

